use crate::jsonrpc_common::{create_error_response_use_code, JsonRpcError, JsonRpcRequest, JsonRpcResponse};
use axum::extract::Path;
use axum::Json;
use common_lib::ErrorCode::{CodeRpcInternalError, CodeRpcInvalidArgument};
use proto_lib::{asset_service_client, test_service_client, QueryRequest, UpdateRequest};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::str::FromStr;
use tonic::transport::Channel;
use tonic::Request;

pub async fn handle_add(request: JsonRpcRequest) -> JsonRpcResponse {
    let params = match request.params {
        Some(Value::Array(params)) if params.len() == 2 => params,
        _ => return JsonRpcResponse {
            jsonrpc: "2.0".to_string(),
            result: None,
            error: Some(JsonRpcError {
                code: -32602,
                message: "Invalid params".to_string(),
                data: None,
            }),
            id: request.id,
        },
    };

    let result = match (params[0].as_f64(), params[1].as_f64()) {
        (Some(a), Some(b)) => Some(Value::Number(serde_json::Number::from_f64(a + b).unwrap())),
        _ => None,
    };

    JsonRpcResponse {
        jsonrpc: "2.0".to_string(),
        result,
        error: None,
        id: request.id,
    }
}


pub async fn handle_asset_update(channel: Channel,params:&Vec<Value>, id:&Value) -> JsonRpcResponse {
    let mut client = asset_service_client::AssetServiceClient::new(channel);
    let user_id = params[0].as_u64().unwrap() as u32;
    let asset = params[1].as_u64().unwrap() as u32 ;
    let change = Decimal::from_str(params[4].as_str().unwrap()).unwrap();;
    if change.is_zero() {
        // todo 通过实现宏简化以下代码
        return create_error_response_use_code(id.as_u64().unwrap(), &CodeRpcInvalidArgument);
    }
    let inc = if change.is_sign_negative() { true} else { false };

    let request = Request::new(UpdateRequest {
        user_id,
        asset,
        inc,
        business: params[2].to_string(),
        business_id: params[3].as_u64().unwrap(),
        change: change.to_string(),
        detail: Some(params[5].to_string()),
    });

    let response = client.update(request).await;
    println!("Response: {:?}", response);
    let message = response.unwrap().into_inner();
    let result = serde_json::to_value(&message)
        .map_err(|e| return create_error_response_use_code(id.as_u64().unwrap(), &CodeRpcInternalError));

    JsonRpcResponse {
        jsonrpc: "2.0".to_string(),
        result: result.ok(),
        error: None,
        id: Some(id.clone()),
    }
}

pub async fn handle_asset_query(channel:Channel,params:&Vec<Value>,id:&Value) -> JsonRpcResponse {
    let mut client = asset_service_client::AssetServiceClient::new(channel);

    let user_id = params[0].as_u64().unwrap() as u32;
    let assets:Vec<u32> = params[1..]
        .iter()
        .map(|v| {
            v.as_u64()
                // .ok_or("Parameter is not a number")
                // .and_then(|n| u32::try_from(n).map_err(|_| "Number too large for u16")).unwrap()
                .ok_or_else(|| return create_error_response_use_code(id.as_u64().unwrap(), &CodeRpcInvalidArgument))
                .and_then(|n| {
                    u32::try_from(n)
                        .map_err(|_| return create_error_response_use_code(id.as_u64().unwrap(), &CodeRpcInvalidArgument))
                }).unwrap()
        })
        .collect();

    let request = Request::new(QueryRequest {
        user_id,
        assets,
    });

    let response = client.query(request).await;
    println!("Response: {:?}", response);
    let message = response.unwrap().into_inner();
    let result = serde_json::to_value(&message)
        .map_err(|e| return create_error_response_use_code(id.as_u64().unwrap(), &CodeRpcInternalError));

    // todo 返回结果多了一层： balances
    JsonRpcResponse {
        jsonrpc: "2.0".to_string(),
        result: result.ok(),
        error: None,
        id: Some(id.clone()),
    }
}

pub async fn handle_test(channel: Channel,params:&Vec<Value>, id:&Value) -> JsonRpcResponse {
    let mut  client = test_service_client::TestServiceClient::new(channel);
    // todo 测试返回map形式的消息包,如下示例:
/*
{
    "error": null,
    "result": {
        "USDT": {
            "margin": "0",
            "available": "10000.00000000000000000000",
            "profit_unreal": "0",
            "frozen": "0",
            "balance_total": "10000.00000000000000000000",
            "transfer": "10000.00000000000000000000"
        }
    },
    "id": 1
}
 */
    JsonRpcResponse {
        jsonrpc: "2.0".to_string(),
        result:None,
        error: None,
        id:Some(id.clone()),
    }
}
//
// #[derive(Serialize, Deserialize)]
// pub struct User {
//     id: u32,
//     name: String,
// }
//
// pub async fn get_user(Path(id): Path<u32>) -> Json<User> {
//     Json(User {
//         id,
//         name: "John Doe".to_string(),
//     })
// }
//
// pub async fn create_user(Json(user): Json<User>) -> Json<User> {
//     Json(user)
// }